<template>
  <div>
    <div id="container" style="width: 100vw; height: 100vh"></div>
    <div class="btnBox">
      <el-button type="primary" @click="startDrawing" :disabled="isDrawing"
        >开始绘制</el-button
      >
      <el-button type="danger" @click="endDrawing" :disabled="!isDrawing"
        >结束绘制</el-button
      >
      <el-button type="success" @click="uploadData">保存</el-button>
      <!-- <el-button type="warning" @click="clearMap">清除</el-button> -->
    </div>
    <div class="display" :style="displaySty" v-show="displayShow">
      <p id="markerId">删除节点</p>
      <p @click="openDialog">插入全景</p>
    </div>
    <p class="deleteLine" v-show="deleteLineShow" :style="deleteLineSty">
      删除此线
    </p>
    <panoramicVue
      :dialogShow="dialogShow"
      :closeDialog="closeDialog"
      :markerInfo="markerInfo"
    ></panoramicVue>
    <dialog id="myDialog">
      <h2>这是一个对话框</h2>
      <div id="pannellum" style="width: 80vw; height: 80vh"></div>
      <button id="closeDialogBtn">关闭对话框</button>
    </dialog>
  </div>
</template>

<script>
import { uniq } from "lodash";
import { addNode, getAllNode } from "@/api/map/node";
import panoramicVue from "./panoramicV2.vue";

export default {
  components: { panoramicVue },
  data() {
    return {
      dialogShow: false,
      polylineList: [],
      markers: [],
      startPoint: null,
      currentId: 1,
      currentPath: [],
      displayShow: false,
      deleteLineShow: false,
      deleteButton: null,
      body: null,
      display: null,
      deleteLine: null,
      map: null,
      isDrawing: false,
      displaySty: "",
      deleteLineSty: "",
      currentMarker: null, //当前右键点击的marker
      markerInfo: {},
      polylineIds: [],
    };
  },
  mounted() {
    // this.initPanoramic()
    this.currentId = localStorage.getItem("markerId") * 1 || 1;
    this.initMap();
    this.body = document.querySelector("#container");
    this.display = document.querySelector(".display");
    this.deleteLine = document.querySelector(".deleteLine");
    window.addEventListener("contextmenu", (event) => {
      event.preventDefault(); // 阻止默认右键菜单
    });
  },
  methods: {
    initPanoramic() {
      const myDialog = document.getElementById("myDialog");
      const closeDialogBtn = document.getElementById("closeDialogBtn");
      closeDialogBtn.addEventListener("click", () => {
        myDialog.close();
      });
      myDialog.showModal();
      let pannellumViewer = pannellum.viewer("pannellum", {
        type: "equirectangular",
        panorama: require("@/assets/images/sphere.jpg"),
        autoLoad: true,
        showControls: true,
      });
      let clickTimeout;
      const CLICK_THRESHOLD = 300; // 点击的最大时间阈值，单位毫秒

      // 添加 mousedown 事件监听器
      pannellumViewer.on("mousedown", function (event) {
        console.log("Mouse down event:", event);

        // 清除之前的超时，防止重复触发
        if (clickTimeout) {
          clearTimeout(clickTimeout);
        }

        // 设置一个新的超时来等待 mouseup 事件
        clickTimeout = setTimeout(() => {
          // 如果超过阈值时间没有 mouseup，则取消这次点击
          console.log("Click cancelled due to timeout.");
          clickTimeout = null;
        }, CLICK_THRESHOLD);
      });

      // 添加 mouseup 事件监听器
      pannellumViewer.on("mouseup", function (event) {
        console.log("Mouse up event:", event);

        // 检查是否在阈值时间内发生了 mouseup
        if (clickTimeout) {
          clearTimeout(clickTimeout); // 清除超时
          clickTimeout = null;

          // 将鼠标事件转换为全景图中的坐标 (yaw, pitch)
          var coordinates = pannellumViewer.mouseEventToCoords(event);
          if (coordinates) {
            var yaw = coordinates[1];
            var pitch = coordinates[0];

            // 创建新的标记
            var newHotSpot = {
              pitch: pitch,
              yaw: yaw,
              type: "custom",
              text: "New Marker",
              tooltip: "You clicked here",
              createElement: function () {
                var element = document.createElement("div");
                element.style.width = "20px";
                element.style.height = "20px";
                element.style.backgroundColor = "red";
                element.style.borderRadius = "50%";
                element.style.position = "absolute"; // 确保标记是绝对定位的
                element.style.pointerEvents = "none"; // 避免标记干扰用户交互
                return element;
              },
            };

            // 将新标记添加到查看器
            try {
              pannellumViewer.addHotSpot(newHotSpot);
              console.log("Marker added at:", pitch, yaw);
            } catch (error) {
              console.error("Failed to add marker:", error);
            }
          } else {
            console.warn(
              "Could not convert mouse event to panorama coordinates."
            );
          }
        }
      });

      // 可选：添加 mousemove 事件监听器以进一步优化用户体验
      pannellumViewer.on("mousemove", function (event) {
        if (clickTimeout) {
          // 如果检测到鼠标移动则取消点击
          clearTimeout(clickTimeout);
          clickTimeout = null;
          console.log("Click cancelled due to mouse movement.");
        }
      });
    },
    initMap() {
      // 初始化地图实例
      this.map = new window.AMap.Map("container", {
        zooms: [16, 25],
        center: [106.505799, 29.504023],
        layers: [new AMap.createDefaultLayer()],
        viewMode: "2D",
      });
      var ext = ".png";
      var googleMapLayer = new AMap.TileLayer({
        getTileUrl: function (x, y, z) {
          return "@/assets/animal/" + z + "/" + x + "/" + y + ext;
        },
        zIndex: 99,
      }).setMap(this.map);
      // 添加点击事件监听器
      this.map.on("click", this.handleMapClick);
      this.map.on("mousedown", (e) => {
        this.displayShow = false;
      });
      this.getListNode();
    },
    // 开始绘图
    startDrawing() {
      if (!this.isDrawing) {
        this.isDrawing = true;
        this.currentPath = []; // 每次开始新的绘制时重置路径
        this.startPoint = null; // 清除选中的起点
      }
    },
    // 结束绘图
    endDrawing() {
      this.isDrawing = false;
    },
    /**
     * 点击地图时触发的回调函数
     * @param {Object} e - 事件对象
     * @param {Object} e.lnglat - 点击的经纬度坐标
     * @description
     * 如果当前处于绘图状态，并且点击了地图，那么：
     * 1. 如果点击的点已经存在，那么将其作为当前点，并添加到当前路径中。
     * 2. 如果点击的点不存在，那么创建一个新的点，添加到当前路径中，并在地图上绘制一个标记。
     * 3. 更新当前Polyline实例，使用当前路径作为Polyline的path。
     */
    handleMapClick(e) {
      if (!this.isDrawing) return;
      const lnglat = e.lnglat;
      let existingMarker = this.findExistingMarker(lnglat);
      if (this.currentPath.length > 1) {
        this.currentPath.splice(0, 1);
      }
      if (existingMarker) {
        this.startPoint = existingMarker;
        this.currentPath.push({
          id: existingMarker.getExtData().id,
          lng: lnglat.lng,
          lat: lnglat.lat,
        });
      } else {
        this.currentPath.push({
          id: this.currentId,
          lng: lnglat.lng,
          lat: lnglat.lat,
        });
        const marker = this.createCustomMarker(
          lnglat.lng,
          lnglat.lat,
          this.currentId
        );
        marker.setExtData({ id: this.currentId }); // 设置扩展数据，用于唯一标识
        this.currentId++;
        marker.on("click", () => this.selectStartPoint(marker));
        marker.on("rightclick", () => this.markerRightClick(marker));
        marker.setMap(this.map);
        this.markers.push(marker);
      }
      this.updatePolyline();
    },

    /**
     * @description
     * 在markers中搜索lnglat坐标相同的marker
     * @param {Object} lnglat - 经纬度坐标
     * @param {number} lnglat.lng - 经度
     * @param {number} lnglat.lat - 纬度
     * @return {Object|null} - 如果存在该marker，返回该marker，否则返回null
     */
    findExistingMarker(lnglat) {
      for (let marker of this.markers) {
        if (
          marker.getPosition().lng === lnglat.lng &&
          marker.getPosition().lat === lnglat.lat
        ) {
          return marker;
        }
      }
      return null;
    },

    /**
     * 创建一个自定义的Marker图标
     * @param {number} lng - 经度
     * @param {number} lat - 纬度
     * @param {number} index - 图标的序号，用于显示在Marker上
     * @return {Object} - 一个AMap.Marker实例，使用Canvas生成的图像作为图标
     */
    createCustomMarker(lng, lat, index, isVrExsit) {
      // 使用Canvas生成的图像作为Marker的图标
      const size = 24; // 图标尺寸
      const iconUrl = this.createCanvas(
        index,
        isVrExsit === "0" ? true : false,
        size
      );
      return new window.AMap.Marker({
        position: [lng, lat],
        title: `点${index}`,
        icon: iconUrl,
        offset: new window.AMap.Pixel(-size / 2, -size / 2),
        clickable: true,
      });
    },
    createCanvas(index, isVrExsit, size = 24) {
      // 创建自定义图标
      const canvas = document.createElement("canvas");
      canvas.width = size;
      canvas.height = size;
      // 获取Canvas绘图上下文
      const ctx = canvas.getContext("2d");
      // 绘制背景圆圈
      ctx.beginPath();
      ctx.arc(size / 2, size / 2, size / 2 - 2, 0, 2 * Math.PI);
      ctx.fillStyle = isVrExsit ? "#ff1000" : "#455b86"; // 圆的颜色
      ctx.fill();
      ctx.lineWidth = 2;
      ctx.strokeStyle = "#FFFFFF"; // 边框颜色
      ctx.stroke();
      // 添加数字文本
      ctx.font = "12px";
      ctx.textAlign = "center";
      ctx.textBaseline = "middle";
      ctx.fillStyle = "#FFFFFF";
      ctx.fillText(index, size / 2, size / 2);
      // 将Canvas内容转换为Base64字符串
      const iconUrl = canvas.toDataURL("image/png");
      return iconUrl;
    },
    /**
     * @function closeDialog
     * @description 关闭对话框，当前Marker保存了VR信息后改变他的颜色
     * @param {number} e - 对话框的返回值 1:取消 2:保存 3:删除
     * @param {object} param - VR信息
     * @param {boolean} isEdit - 是否是编辑Marker
     * @return {void}
     */
    closeDialog(e, param) {
      console.log(e, param);
      // 如果是保存，改变Marker的颜色
      let isVr = false;
      if (e == 2) {
        isVr = true;
      }
      this.dialogShow = false;
      if (this.markerInfo.isEdit || e == 1) return;
      const iconUrl = this.createCanvas(
        this.currentMarker._opts.extData.id,
        isVr
      );
      this.currentMarker.setExtData({
        id: param.nodeId,
        vr: isVr,
      });
      this.currentMarker.setIcon(iconUrl);
    },
    /**
     * @function openDialog
     * @description 打开对话框，用户编辑全景
     * @param {void}
     * @return {void}
     */
    openDialog() {
      if (this.currentId > localStorage.getItem("markerId")) {
        this.$modal.msgError(`请先上传所有节点!`);
        return;
      }
      const list = [];
      this.polylineList.forEach((polyItem) => {
        if (polyItem.ids.includes(this.currentMarker._opts.extData.id)) {
          polyItem.ids.forEach((id) => {
            if (id != this.currentMarker._opts.extData.id) {
              list.push(id);
            }
          });
        }
      });

      this.markerInfo = {
        id: this.currentMarker._opts.extData.id,
        isEdit: this.currentMarker._opts.extData.vr,
        list: uniq(list),
      };
      if (this.markerInfo.list.length == 0) {
        this.$modal.msgError(`该节点没有相邻节点!`);
        return;
      }
      this.dialogShow = true;
      this.displayShow = false;
    },
    /**
     * @function updatePolyline
     * @description 更新当前绘制的Polyline
     * @param {void}
     * @return {void}
     */
    updatePolyline() {
      if (this.currentPath.length < 2) return;
      const path = this.currentPath.map((p) => [p.lng, p.lat]);
      const polyline = new window.AMap.Polyline({
        path: path,
        strokeColor: "#94D3F7",
        strokeOpacity: 1,
        strokeWeight: 6,
        strokeStyle: "solid",
        lineJoin: "round",
      });
      polyline.setMap(this.map);
      polyline.on("rightclick", (e) => {
        const pixel = this.map.lngLatToContainer(e.lnglat);
        this.showDeleteButton(pixel, polyline);
      });
      // 鼠标移动时改变鼠标样式
      polyline.on("mousemove", () => {
        this.body.style.cursor = "crosshair";
      });
      polyline.on("mouseout", () => {
        this.body.style.cursor = "default";
      });
      this.polylineList.push({
        ids: [this.currentPath[0].id, this.currentPath[1].id],
        polyline,
      });
    },

    /**
     * 选择起始点
     * @param {AMap.Marker} marker - 选择的起始点标记
     * @description
     * 如果当前正在绘图，则立即使用选中的起始点作为下一个点
     */
    selectStartPoint(marker) {
      this.startPoint = marker;
      const lng = this.startPoint.getPosition();
      // 如果当前正在绘图，则立即使用选中的起始点作为下一个点
      if (this.isDrawing) {
        this.handleMapClick({
          lnglat: {
            lng: lng.lng,
            lat: lng.lat,
          },
        });
      }
    },

    /**
     * 清除地图上绘制的所有多段线和标记，重置所有状态
     */
    clearMap() {
      this.polylineList.forEach((item) => item.polyline.setMap(null));
      this.polylineList = [];
      this.markers.forEach((marker) => marker.setMap(null));
      this.markers = [];
      this.currentPath = [];
      this.startPoint = null;
      this.currentId = localStorage.getItem("markerId") * 1 || 1;
      this.displayShow = false;
      this.dialogShow = false;
    },

    /**
     * 删除指定的Marker和相关的Polyline
     * @param {AMap.Marker} e - 待删除的Marker实例
     * @description
     * 1. 遍历当前所有的Polyline实例，查找与待删除Marker关联的Polyline，并从地图上移除。
     * 2. 从polylineList中删除已移除的Polyline。
     * 3. 从markers列表中删除待删除的Marker。
     */
    deleteMarker(e) {
      this.displayShow = false;
      this.currentPath = [];
      const arr = this.polylineList;
      for (let i = 0; i < arr.length; i++) {
        if (this.polylineList[i].ids.includes(e._opts.extData.id)) {
          this.polylineList[i].polyline.setMap(null);
          this.polylineList.splice(i, 1);
          i--;
        }
      }
      e.remove();
      this.markers = this.markers.filter(
        (marker) => marker._amap_id !== e._amap_id
      );
    },
    /**
     * 在pixel所在的位置显示删除按钮，点击按钮时删除polyline
     * @param {Object} pixel -  pixel对象
     * @param {Object} polyline -  Polyline对象
     */
    showDeleteButton(pixel, polyline) {
      this.deleteLineSty = `left:${pixel.x + "px"};top:${pixel.y + "px"} `;
      // 绑定删除按钮点击事件
      this.deleteLineShow = true;
      this.deleteLine.onclick = () => {
        this.map.remove(polyline);
        this.deleteLineShow = false;
      };
      for (let i = 0; i < this.polylineList.length; i++) {
        if (this.polylineList[i].polyline._amap_id === polyline._amap_id) {
          this.polylineList.splice(i, 1);
          break;
        }
      }
      // 绑定鼠标移出按钮区域隐藏按钮的事件
      this.deleteLine.onmouseout = () => {
        this.deleteLineShow = false;
      };
    },

    /**
     * 上传当前地图上的所有标记和Polyline到服务器
     * @description
     * 1. 遍历当前所有的Marker实例，分别处理每个Marker。
     * 2. 对于每个Marker，首先将其基本信息（id、经度、纬度）push到datalist数组中。
     * 3. 然后，遍历当前所有的Polyline实例，查找与当前Marker关联的Polyline，并将关联的其他Marker的id push到datalist的对应项的ids数组中。
     * 4. 由于某个Polyline可能与多个Marker关联，所以需要去重datalist的ids数组。
     */
    uploadData() {
      this.$modal.loading("保存中...");
      let datalist = [];
      this.markers.forEach((item, index) => {
        datalist.push({
          id: item._opts.extData.id,
          ids: {},
          idList: [],
          longitude: item.getPosition().lng,
          latitude: item.getPosition().lat,
        });
        this.polylineList.forEach((polyItem) => {
          if (polyItem.ids.includes(item._opts.extData.id)) {
            datalist[index].idList.push(...polyItem.ids);
          }
        });
        datalist[index].idList = uniq(datalist[index].idList).filter(
          (e) => e !== item._opts.extData.id
        );
        datalist[index].ids = Object.fromEntries(
          datalist[index].idList.map((id) => [id, 1])
        );
      });
      localStorage.setItem("markerId", this.currentId);
      addNode(datalist).then((res) => {
        this.$modal.closeLoading();
        console.log(res);
      });
    },
    /**
     * 查询所有节点并绘制到地图上
     * @description
     */
    getListNode() {
      this.$modal.loading("正在绘制节点路线，请稍候...");
      getAllNode().then((res) => {
        res.data.forEach((item) => {
          this.createMarker(item);
          item.ids.forEach((idItem) => {
            const path = res.data.find((e) => e.id === idItem.id);
            if (path) {
              this.createPolyline(item, path);
            }
          });
        });
        this.$modal.closeLoading();
      });
    },
    /**
     * 创建一个Marker
     * @param {number} lng - 经度
     * @param {number} lat - 纬度
     * @param {number} id - Marker的ID
     * @description
     * 1. 通过createCustomMarker方法创建一个自定义的Marker
     * 2. 设置Marker的扩展数据，用于唯一标识
     * 3. 监听Marker的点击事件，并在点击时调用selectStartPoint
     * 4. 监听Marker的右键点击事件，并在点击时弹出删除确认框
     * 5. 将Marker添加到地图上
     */
    createMarker(item) {
      const marker = this.createCustomMarker(
        item.longitude,
        item.latitude,
        item.id,
        item.isVrNode
      );
      marker.setExtData({
        id: item.id,
        vr: item.isVrNode === "0" ? true : false,
      }); // 设置扩展数据，用于唯一标识
      marker.on("click", () => this.selectStartPoint(marker));
      marker.on("rightclick", () => this.markerRightClick(marker));
      marker.setMap(this.map);
      this.markers.push(marker);
    },
    /**
     * Marker右键点击事件
     * @param {Object} e - Marker对象
     * @description
     * 1. 保存当前Marker对象
     * 2. 显示删除确认框
     * 3. 监听删除确认框的点击事件，并在点击时删除Marker
     */
    markerRightClick(e) {
      this.currentMarker = e;
      this.displayShow = true;
      this.displaySty = `left:${e._style.left};top:${e._style.top}`;
      const markerId = document.getElementById("markerId");
      markerId.onclick = () => {
        this.deleteMarker(e);
      };
    },
    createPolyline(item, path) {
      if (this.polylineIds.find((e) => e[0] === path.id && e[1] === item.id))
        return;
      this.polylineIds.push([item.id, path.id]);
      this.currentPath = [
        {
          id: item.id,
          lng: item.longitude,
          lat: item.latitude,
        },
        {
          id: path.id,
          lng: path.longitude,
          lat: path.latitude,
        },
      ];
      this.updatePolyline();
    },
  },
};
</script>

<style scoped>
#container {
  width: 100%;
  height: 100%;
}
.display {
  position: absolute;
  z-index: 88;
  box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.4);
  background-color: #fff;
  border-radius: 5px;
  padding: 4px 0;
  font-size: 14px;
  line-height: 30px;
  text-align: center;
  width: 100px;
}
.display > p:hover {
  cursor: pointer;
  color: #ff1000;
  font-weight: bold;
}
.deleteLine {
  position: absolute;
  z-index: 88;
  line-height: 26px;
  text-align: center;
  width: 80px;
  border-radius: 5px;
  box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.4);
  background-color: #fff;
  padding: 4px 0;
  font-size: 12px;
}
.deleteLine:hover {
  cursor: pointer;
  color: #ff1000;
  font-weight: bold;
}
.btnBox {
  position: absolute;
  top: 20px;
  right: 20px;
  z-index: 111;
}

/* 对整个对话框进行样式设置 */
dialog {
  width: 80%;
  border: 1px solid #ccc;
  border-radius: 5px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
  padding: 20px;
  background-color: white;
}

/* 对话框标题样式 */
dialog h2 {
  margin-top: 0;
}

/* 关闭按钮样式 */
#closeDialogBtn {
  margin-top: 10px;
  background-color: #f44336;
  color: white;
  border: none;
  padding: 10px 20px;
  border-radius: 3px;
  cursor: pointer;
}

#openDialogBtn {
  padding: 10px 20px;
  background-color: #008cba;
  color: white;
  border: none;
  border-radius: 3px;
  cursor: pointer;
  margin-bottom: 10px;
}
</style>
